package cate.game.play.fighter;

import cate.common.table.d.GDCamp;
import cate.common.table.d.GDFight;
import cate.common.table.d.GDHero;
import cate.game.play.buff.Buff;
import cate.game.play.buff.BuffHandler;
import cate.game.play.part.FightTeam;
import cate.game.play.proce.action.ctx.ActionCtx;
import cate.game.play.proce.action.ctx.SkillActionCtx;
import cate.game.play.proce.action.ctx.TimeActionCtx;
import cate.game.play.proce.move.MoveCtx;
import cate.game.play.proce.result.DeadResult;
import cate.game.play.skill.FighterCD;
import cate.game.play.skill.Skill;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Transient;

import java.util.Comparator;

@NoteClass("战斗者")
@Getter
@Setter
public abstract class Fighter<T extends Fighter> {

	@NoteField("战斗者类型")
	public byte type;

	@NoteField("战斗者uid")
	public String uid;

	@NoteField("战斗对象的剧本临时ID")
	protected int pid;

	@NoteField("所属队伍")
	public byte team;

	@NoteField("所属队伍信息")
	@Transient
	@JsonIgnore
	public transient FightTeam fightTeam;

	@NoteField("战斗对象各种战斗属性")
	public FightAttrGroup attr = new FightAttrGroup();

	@NoteField("战斗者身上的技能")
	@Transient
	@JsonIgnore
	public transient FightSkills skill = new FightSkills();

	@NoteField("战斗者身上的buff")
	@Transient
	@JsonIgnore
	public transient FightBuffs buff = new FightBuffs();

	@NoteField("CD管理")
	@Transient
	@JsonIgnore
	public transient FighterCD cd = new FighterCD();

	@NoteField("状态管理")
	@Transient
	@JsonIgnore
	public transient FighterStatus status = new FighterStatus();

	@NoteField("战斗者的战绩")
	@JsonIgnore
	public FighterPerformance performance = new FighterPerformance();


	@JsonIgnore
	public byte getJob() {
		return GDHero.Job.NULL;
	}

	@JsonIgnore
	public byte getCamp() {
		return GDCamp.Type.NULL;
	}

	@JsonIgnore
	public byte getPos(){
		return 0;
	}

	@JsonIgnore
	public void setPos(byte pos){}

	@JsonIgnore
	public int getLevel(){return 0;}

	@JsonIgnore
	public int getStar(){return 0;}

	@JsonIgnore
	public int getProtoId() { return 0; }

	public void init() {
		attr.init(this);
		skill.init(this);
		buff.init(this);
	}

	/** 是否活着 */
	@JsonIgnore
	public boolean isAlive() {
		return !isDead();
	}

	/** 是否死了 */
	@JsonIgnore
	public boolean isDead(){
		return false;
	}

	/**
	 * 设置死亡状态
	 * @param dead
	 */
	public void setDead(boolean dead){

	}

	/**
	 * 是否允许添加buff
	 * @param action
	 * @param buffToAdd
	 * @return
	 */
	public boolean allowAddBuff(ActionCtx action, Buff buffToAdd) {
		if (!GDFight.Fighter.isAreaFighter(type)) {
			return false;
		}
		if(status.isGhost()){
			return false;
		}
		//免疫buff检测
		for (BuffHandler handler : buff.getHandlers()) {
			if (!handler.allowAddBuff(action, buffToAdd)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 允许进行血量变更
	 * @return
	 */
	public boolean allowChangeHp() {
		if (!GDFight.Fighter.isAreaFighter(type)) {
			return false;
		}
		if (status.isGhost()) {
			return false;
		}
		return true;
	}

	/**
	 * 检查死亡
	 */
	public void checkDead(ActionCtx action, Fighter killer) {
		if (attr.hpCur() <= 0) {
			this.attr.hpCur(0.0);
			boolean deadCurAct = !isDead();
			this.setDead(true);
			if (deadCurAct) {
				action.addResult(new DeadResult().pidSet(this.pid));
				FighterPerformance.recKill(action, killer, this);
				killer.skill.forHandlers(a -> a.onKill(action, this));
				killer.buff.forHandlers(a -> a.onKill(action, this));
				//通知场上有人即将死了
				action.getTeamVs().forAreaFighters(f -> {
					f.skill.forHandlers(s -> s.beforeOtherDead(action, this));
				});
				this.onDead(action, killer);
				//通知场上有单位死了
				action.getTeamVs().forAreaFighters(f -> {
					f.skill.forHandlers(s -> s.onOtherDead(action, killer, this));
				});
				if (action.isActiveSkill()) {
					status.setMarkDead(true);
				}else {
					handleImmediateRebirth(action);
				}
			}
		} else {
			this.setDead(false);
		}
	}

	public void handleImmediateRebirth(ActionCtx action) {
		buff.getHandlers().forEach(h->h.immediateRebirth(action));
		skill.getHandlers().stream().sorted(Comparator.comparing(h -> -h.priority())).
				forEach(h -> h.immediateRebirth(action));
		if (isDead()) {
			skill.getHandlers().forEach(h -> h.onDeadNoRebirth(action));
		}
	}

	/** 死亡时 */
	public void onDead(ActionCtx action, Fighter killer) {
		this.buff.onDead(action, killer);
		this.skill.forHandlers(s -> s.onDead(action, killer));
		if (action instanceof SkillActionCtx) {
			((SkillActionCtx) action).getTurn().removeAppend(this);
		}
	}

	public boolean allowUseSkill(Skill skill) {
		if (!isAlive()) {
			return false;
		}
		if (!skill.param.isIgnCtrlMove() && skill.owner.buff.noMoveWithCtrl()) {
			return false;
		}
		if (skill.param.targetInValid()) {
			return false;
		}
		return true;
	}

	/** 本人行动前 */
	public void beforeOwnerMove(MoveCtx move) {
		TimeActionCtx action = move.buildTimeAction();
		this.skill.forHandlers(a -> a.beforeOwnerMove(move,action));
		this.buff.forHandlers(a -> a.beforeOwnerMove(move,action));
	}

	/** 本人行动结束时 */
	public void onOwnerMoveDone(MoveCtx move) {
		TimeActionCtx action = move.buildTimeAction();
		this.skill.forHandlers(a -> a.onOwnerMoveDone(move,action));
		this.buff.forHandlers(a -> a.onOwnerMoveDone(move,action));

	}

	/** 本人行动轮次结束时（可能因为控制或者死亡跳过了本次行动 但还是会执行）*/
	public void onOwnerMoveOver(){
		this.attr.onOwnerMoveOver();
		this.status.onOwnerMoveOver();
	}


	/** 拷贝 */
	public abstract T copy();


	/** 读取 */
	public void readFrom(T tar) {
		this.uid = tar.uid;
		this.pid = tar.pid;
		this.type = tar.type;
		this.team = tar.team;
		this.fightTeam = tar.fightTeam;
		this.attr = tar.attr.copy();
		this.skill = tar.skill;
		this.cd = tar.cd.copy();
		this.status = tar.status.copy();
		this.performance = tar.performance.copy();
	}



	@NoteField("是否进行过登场处理")
	@Transient
	@JsonIgnore
	protected boolean enter;

	public void handleFirstEnter(ActionCtx action){

	}

}
